﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;
using DevExpress.Web.ASPxEditors;
using TireService.Data;
using System.Drawing;
using DevExpress.Utils;
using System.Configuration;
using DevExpress.Web.ASPxCallback;
using System.IO;

namespace TireService.Website.Kunde
{
    public partial class Booking : System.Web.UI.Page
    {
        private int _customerid;
        private int _taskid;
        private int _existingservicecarscheduledetailid;
        private int _selectedzipcode;
        private List<DateTime> _freedates;
        private bool _freetimeslots = false;

        public int CustomerId
        {
            get
            {
                return this._customerid;
            }
            set
            {
                this._customerid = value;
            }
        }

        public int TaskId
        {
            get
            {
                return this._taskid;
            }
            set
            {
                this._taskid = value;
            }
        }

        public int ExistingServiceCarScheduleDetailId
        {
            get
            {
                return this._existingservicecarscheduledetailid;
            }
            set
            {
                this._existingservicecarscheduledetailid = value;
            }
        }

        public List<DateTime> FreeDates
        {
            get
            {
                return this._freedates;
            }
            set
            {
                this._freedates = value;
            }
        }

        public int SelectedZipCode
        {
            get
            {
                return this._selectedzipcode;
            }
            set
            {
                this._selectedzipcode = value;
            }
        }

        public bool FreeTimeSlots 
        {
            get
            {
                return this._freetimeslots;
            }
            set
            {
                this._freetimeslots = value;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack != true)
            {
                try
                {
                    // Testing value for free timeslot interval
                    hfFreeTimeIntervalIncluded["FreeTimeIntervalIncluded"] = true;
                    hfFreeTimeIntervalIncluded["BuyTimeInterval"] = false;

                    // Testing purpose
                    //Guid userid = new Guid("5a2cfd97-db62-488b-9657-836abe70836c");
                    //Guid userid = new Guid("ac50f04f-69f7-4edd-937f-84d02d6dcc54");


                    // Get user
                    Guid userid = new Guid();
                    bool LoginWithUserId = true;

                    if (HttpContext.Current.User.Identity.IsAuthenticated)
                    {
                        userid = new Guid(Membership.GetUser().ProviderUserKey.ToString());
                    }
                    else
                    {
                        try
                        {
                            userid = new Guid(Request.QueryString["uid"].ToString());
                        }
                        catch (Exception)
                        {
                            try
                            {
                                LoginWithUserId = (!(Request.QueryString["did"].ToString() != string.Empty & Request.QueryString["cid"].ToString() != string.Empty));
                            }
                            catch (Exception)
                            {
                                // No valid user
                                Response.Redirect("~/Login.aspx");
                            }
                        }
                    }

                    // Initiate data layer
                    TireServiceDB db = new TireServiceDB();

                    // Get customer based on logged in user
                    Customer customer = new Customer();
                    
                    if (LoginWithUserId)
                    {
                        customer = db.GetCustomer(userid);
                    }
                    else
                    {
                        customer = db.GetCustomer(Convert.ToInt32(Request.QueryString["cid"].ToString()));
                    }

                    if (customer == null)
                    {
                        // Customer was not found
                        throw new ArgumentException("Kunde ikke fundet - booking kunne ikke foretages. Venligst kontakt vores kundesupport hvis der er sket en fejl.");
                    }
                    else
                    {
                        // Set propertie with customerid
                        this.CustomerId = customer.CustomerId;

                        // Update sessions with customer
                        Session["BookingCustomerId"] = customer.CustomerId;

                        // Bind data to select address panel
                        ddlSelectAddress.Items.Clear();
                        string add1 = customer.Address + "|" + customer.ZipCode + "|" + customer.City;
                        string add2 = customer.SecondaryAddress + "|" + customer.SecondaryZipCode + "|" + customer.SecondaryCity;
                        string add3 = "-- Anden adresse --";

                        ddlSelectAddress.Items.Add(add1, 0);
                        ddlSelectAddress.Items.Add(add2, 1);
                        ddlSelectAddress.Items.Add(add3, 2);

                        List<BusinessCarListView> cars = GetCarList(db, customer.CustomerId);

                        if (cars.Count == 0)
                        {
                            // Customer has no cars that need tirechange (based on status)
                            throw new ArgumentException("Ingen biler står registreret til at skulle have skiftet hjul. Venligst kontakt vores kundesupport hvis der er sket en fejl.");
                        }
                        else
                        {
                            // Bind carlist to gridview
                            gvSelectCar.DataSource = cars.ToList();
                            gvSelectCar.DataBind();

                            if (cars.Count == 1)
                            {
                                // Preselect the car on client side
                                Page.ClientScript.RegisterStartupScript(this.GetType(), "ClientScriptGoToSelectAddress", "SelectCar(this, " + cars.First().CarId.ToString() + ");", true);
                            }
                        }

                    }
                }
                catch (Exception ex)
                {
                    
                    
                }
            }
        }

        private void SelectCar(TireServiceDB db, BusinessCarListView car)
        {
            // Show details in GUI on selected car
            lblSelectedCarRegistrationNumberValue.Text = car.RegistrationNumber;
            lblSelectedCarBrandDescriptionValue.Text = car.CarBrandDescription;
            pExistingBooking.Visible = false;

            // Tirechange not yet booked/planned
            if (car.CarStatusId == (int)Shared.CarStatus.AwaitsTireChangePlanning)
            {
                // Car awaits tirechange planning (Booking)
                int[] tasktypestatus = new int[] { (int)Shared.TaskTypeStatus.ServiceDrive_Created, (int)Shared.TaskTypeStatus.ServiceDrive_Replan };

                List<Task> tasks = db.GetTasksByCarAndTaskTypeStatus(car.CarId, tasktypestatus);

                int taskid = 0;

                foreach (Task task in tasks)
                {
                    // Check if taskdetails contain TireChange
                    if (db.TaskDetails.Where(p => p.TaskDetailTypeId == (int)Shared.TaskDetailType.ServiceDrive_ChangeTire & p.TaskId == task.TaskId).Count() == 1)
                    {
                        taskid = task.TaskId;

                        // Check if task is dependent on other task is done first
                        if (task.DependentTaskId != null)
                        {
                            Task dependenttask = db.GetTask(Convert.ToInt32(task.DependentTaskId));
                            if (dependenttask.CompletionDate == null)
                            {
                                throw new ArgumentException("Hjulskift kan ikke bookes, da der ligger anden opgave på bil der skal udføres først - kontakt venligst vores kundesupport for at aftale booking.");
                            } 
                        }
                    }
                }

                if (taskid != 0)
                {
                    // Store TaskId for booking creation
                    this.TaskId = taskid;

                    // Update session with taskid
                    Session["BookingTaskId"] = taskid;
                }
                else
                {
                    throw new ArgumentException("Hjulskift allerede planlagt for din bil - kontakt venligst vores kundesupport for at ændre din booking.");
                }
            }

            // Tirechange already booked / planned
            if (car.CarStatusId == (int)Shared.CarStatus.PlannedTireChange)
            {
                // Car has already tirechange planned (Booked) - change date
                int[] tasktypestatus = new int[] { (int)Shared.TaskTypeStatus.ServiceDrive_Planned };

                List<Task> tasks = db.GetTasksByCarAndTaskTypeStatus(car.CarId, tasktypestatus);

                int taskid = 0;

                foreach (Task task in tasks)
                {
                    // Check if taskdetails contain TireChange
                    if (db.TaskDetails.Where(p => p.TaskDetailTypeId == (int)Shared.TaskDetailType.ServiceDrive_ChangeTire & p.TaskId == task.TaskId).Count() == 1)
                    {
                        taskid = task.TaskId;
                    }
                }

                if (taskid != 0)
                {
                    // Store TaskId for booking creation
                    this.TaskId = taskid;

                    // Update session with taskid
                    Session["BookingTaskId"] = taskid;

                    // Task was found
                    ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetailByTaskId(taskid);

                    if (detail == null)
                    {
                        throw new ArgumentException("Hjulskift allerede planlagt for din bil - kontakt venligst vores kundesupport for at ændre din booking.");
                    }
                    else
                    {
                        // Set page propertie
                        this.ExistingServiceCarScheduleDetailId = detail.ServiceCarScheduleDetailId;

                        // Update sessions with existing booked schedule
                        Session["BookingExistingServiceCarScheduleDetailId"] = detail.ServiceCarScheduleDetailId;

                        // Show already planned date in GUI
                        pExistingBooking.Visible = true;

                        lblExistingBookingAddressValue.Text = detail.ToAddress + ", " + detail.ToZipCode + " " + detail.ToCity;
                        lblExistingBookingDateValue.Text = detail.ScheduleDate.ToShortDateString();
                        lblExistingBookingTimeslotValue.Text = string.Format("{0:t}", detail.StartTime) + " - " + string.Format("{0:t}", detail.EndTime);
                    }
                }
                else
                {
                    throw new ArgumentException("Hjulskift allerede planlagt for din bil - kontakt venligst vores kundesupport for at ændre din booking.");
                }
            }

            // This scenario will never occure, due to filter
            if (car.CarStatusId != (int)Shared.CarStatus.AwaitsTireChangePlanning & car.CarStatusId != (int)Shared.CarStatus.PlannedTireChange)
            {
                // Car status is not correct for tirechange booking
                throw new ArgumentException("Ingen bil står angivet til at skulle have skiftet hjul. Venligst kontakt vores kundesupport hvis der er sket en fejl.");
            }
        }

        /// <summary>
        /// Function that return a list of cars with status Awaiting or Planned TireChange
        /// </summary>
        /// <param name="db">Connection to database</param>
        /// <param name="CustomerId">Id on customer cars is related to</param>
        /// <returns>List with BusinessCarListView objects</returns>
        private static List<BusinessCarListView> GetCarList(TireServiceDB db, int CustomerId)
        {
            // Define array with status to search for (Awaits booking or already booked)
            int[] carstatus = new int[] { (int)Shared.CarStatus.AwaitsTireChangePlanning, (int)Shared.CarStatus.PlannedTireChange };

            // Load cars
            List<BusinessCarListView> cars = db.GetCustomerCars(CustomerId).Where(d => carstatus.Contains(d.CarStatusId)).ToList();
            return cars;
        }

        /// <summary>
        /// Postback function that updates car list based on selected customerid
        /// </summary>
        protected void gvSelectCar_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
        {
            TireServiceDB db = new TireServiceDB();
            gvSelectCar.DataSource = GetCarList(db, this.CustomerId).ToList();
            gvSelectCar.DataBind();
        }

        /// <summary>
        /// Function that is raised from client side - Not used yet
        /// </summary>
        protected void callbackSelectCarPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {

            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side when car is selected and update GUI with available addresses based on logged in customer
        /// </summary>
        protected void callbackSelectAddressPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Initiate datalayer
                TireServiceDB db = new TireServiceDB();

                // Bind zipcode list (Only DK ZipCodes)
                //ddlZipCode.DataSource = db.GetCountryZipCodeLists(0);
                //ddlZipCode.ValueField = "ZipCode";
                //ddlZipCode.DataBind();

                // Get car
                BusinessCarListView car = db.BusinessCarListViews.SingleOrDefault(p => p.CarId == Convert.ToInt32(e.Parameter));

                if (car != null)
                {
                    // Update gui based on selected car
                    SelectCar(db, car);

                    // Update session with car selected
                    Session["BookingCarId"] = car.CarId;
                }
                else
                {
                    throw new ArgumentException("Den valgte bil står ikke angivet til at skulle have skiftet hjul - kontakt venligst vores kundesupport.");
                }
            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side and update GUI with available dates based on selected address/zipcode
        /// </summary>
        protected void callbackSelectDatePanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Instantiate data layer
                TireServiceDB db = new TireServiceDB();

                // Get values (0: SelectedAddress (0: Primary, 1: Secondary, 2: New one), 1: ZipCode)
                string[] param = e.Parameter.Split('|');

                int SelectedAddress = Convert.ToInt32(param[0]);
                string ZipCode = param[1].ToString();

                // Get dates where we will be driving in zipcode area and where theres i free capacity in the future
                var AvailableDatesOnZipCode = from p in db.ServiceGeographicalAreaZipCodeLists
                                              join y in db.ServiceCarGeographicalAreaAllocations on p.ServiceGeoAreaId equals y.ServiceGeoAreaId into py
                                              from z in py.DefaultIfEmpty()
                                              join v in db.ServiceCarSchedules on
                                              new { Col1 = z.ServiceCarId, Col2 = z.ScheduleDate }
                                              equals
                                              new { Col1 = v.ServiceCarId, Col2 = v.ScheduleDate }
                                              into pv
                                              from x in pv.DefaultIfEmpty()
                                              // Filter parameters: ZipCode, Date, None GroupServiceDay, Available capacity
                                              where p.ZipCode == ZipCode & z.ScheduleDate > DateTime.Now.AddDays(1) & x.GroupServiceCarScheduleId == null & db.ServiceCarScheduleDetails.Where(q => q.ServiceCarId == z.ServiceCarId & q.ScheduleDate == z.ScheduleDate & q.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available).Count() > 0
                                              select new
                                              {
                                                  z.ScheduleDate
                                                  //                      Capacity = db.ServiceCarScheduleDetails.Where(q => q.ServiceCarId == p.ServiceCarId & q.ScheduleDate == p.ScheduleDate).Count(),
                                                  //                      AvailableCapacity = db.ServiceCarScheduleDetails.Where(q => q.ServiceCarId == p.ServiceCarId & q.ScheduleDate == p.ScheduleDate & q.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available).Count(),
                                                  //                      AreaAllocated = (bool)(z.ServiceGeoAreaId == null ? false : true)
                                              };

                // Update session with address selection
                Session["BookingAddressChoice"] = ddlSelectAddress.Value;
                Session["BookingAddress"] = txtAddress.Text;
                Session["BookingZipCode"] = txtZipCode.Text; // ddlZipCode.Value;
                Session["BookingCity"] = db.CountryZipCodeLists.SingleOrDefault(p => p.ZipCode == txtZipCode.Text.ToString()).City; //db.CountryZipCodeLists.SingleOrDefault(p => p.ZipCode == ddlZipCode.Value.ToString()).City;


                if (AvailableDatesOnZipCode.Count() == 0)
                {
                    throw new ArgumentException("Ingen ledige tider kunne findes. Venligst kontakt vores kundesupport for en tid.");
                }
                else
                {
                    // Clear free dates if contain old values
                    if (this.FreeDates != null)
                    {
                        this.FreeDates.Clear();    
                    }

                    List<DateTime> dates = new List<DateTime>();

                    foreach (var date in AvailableDatesOnZipCode.Distinct().ToList())
                    {
                        dates.Add(date.ScheduleDate);
                    }

                    this.FreeDates = dates;

                    ddlSelectDate.DataSource = dates;
                    //ddlSelectDate.DisplayFormatString = "d";
                    //ddlSelectDate.Properties.DisplayFormat.FormatType = FormatType.DateTime;
                    //ddlSelectDate.Properties.DisplayFormat.FormatString = "d";

                    //ddlSelectDate.DisplayFormatString = "d";
                    //comboBoxSettings.Properties.TextField = "DateAsSting";
                    //comboBoxSettings.Properties.ValueField = "DateAsDate";
                    //comboBoxSettings.Properties.ValueType = typeof(DateTime);

                    ddlSelectDate.DataBind();
                }
            }
            catch (Exception ex)
            {
                
                // Error
                //throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side when date is selected and update GUI with timeslots based on selection
        /// </summary>
        protected void callbackSelectTimeslotPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Instantiate data layer
                TireServiceDB db = new TireServiceDB();

                // Get selected date
                //DateTime date = Convert.ToDateTime(calendarAvailableDates.Value);
                DateTime date = Convert.ToDateTime(ddlSelectDate.Value);

                // Session with selected date
                Session["BookingDate"] = Convert.ToDateTime(ddlSelectDate.Value);

                // Show timeslots
                var Timeslots = from p in db.ServiceCarScheduleDetails
                                join v in db.ServiceCarSchedules on
                                new { Col1 = p.ServiceCarId, Col2 = p.ScheduleDate }
                                equals
                                new { Col1 = v.ServiceCarId, Col2 = v.ScheduleDate }
                                into pv
                                from x in pv.DefaultIfEmpty()

                                join y in db.ServiceCarGeographicalAreaAllocations on
                                new { Col1 = x.ServiceCarId, Col2 = x.ScheduleDate }
                                equals
                                new { Col1 = y.ServiceCarId, Col2 = y.ScheduleDate }
                                into xy 
                                from w in xy.DefaultIfEmpty()

                                join a in db.ServiceGeographicalAreaZipCodeLists on w.ServiceGeoAreaId equals a.ServiceGeoAreaId
                                into wa
                                from b in wa.DefaultIfEmpty()
                                // Filter parameters: ZipCode, Date, None GroupServiceDay, Available capacity
                                //where b.ZipCode == ddlZipCode.Value.ToString() & p.ScheduleDate == date & x.GroupServiceCarScheduleId == null & p.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available
                                where b.ZipCode == txtZipCode.Text.ToString() & p.ScheduleDate == date & x.GroupServiceCarScheduleId == null & p.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available
                                select new
                                {
                                    p.ScheduleDate,
                                    p.ServiceCarScheduleDetailId,
                                    p.StartTime,
                                    p.EndTime,

                                };


                //var Timeslots = from p in db.ServiceGeographicalAreaZipCodeLists
                //                              join y in db.ServiceCarGeographicalAreaAllocations on p.ServiceGeoAreaId equals y.ServiceGeoAreaId into py
                //                              from z in py.DefaultIfEmpty()
                //                              join v in db.ServiceCarSchedules on
                //                              new { Col1 = z.ServiceCarId, Col2 = z.ScheduleDate }
                //                              equals
                //                              new { Col1 = v.ServiceCarId, Col2 = v.ScheduleDate }
                //                              into pv
                //                              from x in pv.DefaultIfEmpty()
                //                              join a in db.ServiceCarScheduleDetails on x.ServiceCarScheduleId equals a.ServiceCarScheduleDetailId
                //                              into pa
                //                              from w in pa.DefaultIfEmpty()
                //                              // Filter parameters: ZipCode, Date, None GroupServiceDay, Available capacity
                //                              where p.ZipCode == txtZipCode.Text & z.ScheduleDate == date & x.GroupServiceCarScheduleId == null & db.ServiceCarScheduleDetails.Where(q => q.ServiceCarId == z.ServiceCarId & q.ScheduleDate == z.ScheduleDate & q.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available).Count() > 0
                //                              select new
                //                              {
                //                                  z.ScheduleDate,
                //                                  w.ServiceCarScheduleDetailId,
                //                                  w.StartTime,
                //                                  w.EndTime,
                                                  
                //                              };

                var t = from p in Timeslots.ToList()
                        select new
                            {
                                p.ScheduleDate,
                                p.ServiceCarScheduleDetailId,
                                Interval = string.Format("{0:t}", p.StartTime) + " - " + string.Format("{0:t}", p.EndTime),
                                Fullday = "kl. 8 - 16"
                            };
                

                //Interval = w.StartTime.Ticks).ToString("HH:mm") + " - " + (w.EndTime.Ticks).ToString("HH:mm"),

                if (Convert.ToBoolean(e.Parameter))
                {
                    rblSelectTimeslot.DataSource = t.ToList();
                    rblSelectTimeslot.ValueField = "ServiceCarScheduleDetailId";
                    rblSelectTimeslot.TextField = "Interval";
                    rblSelectTimeslot.DataBind();

                    Session["BookingFullDay"] = false;
                }
                else
                {
                    Session["BookingFullDay"] = true;

                    rblSelectTimeslot.Items.Clear();
                    DevExpress.Web.ASPxEditors.ListEditItem fullday = new DevExpress.Web.ASPxEditors.ListEditItem();
                    fullday.Value = date.ToShortDateString();
                    fullday.Text = "Hele dage: kl. 8 - 16";
                    rblSelectTimeslot.Items.Add(fullday);
                }

                

            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side when timeslot is selected - save booking and update GUI, show approval/confirmation panel
        /// </summary>
        protected void callbackApproveBookingPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Book schedule

                // Get values
                int customerid = (int)Session["BookingCustomerId"];
                int carid = (int)Session["BookingCarId"];
                int taskid = (int)Session["BookingTaskId"];
                int existingservicecarscheduledetailid = 0;
                if (Session["BookingExistingServiceCarScheduleDetailId"] != null)
                {
                    existingservicecarscheduledetailid = (int)Session["BookingExistingServiceCarScheduleDetailId"];
                }
                DateTime selecteddate = (DateTime)Session["BookingDate"];
                //int AddressChoice = (int)Session["BookingAddressChoice"];
                string address = Session["BookingAddress"].ToString();
                string zipcode = Session["BookingZipCode"].ToString();
                string city = Session["BookingCity"].ToString();

                int selectedservicecarscheduledetailid = 0;

                // Check booking type - full day or interval
                if ((bool)Session["BookingFullDay"])
                {
                    // Calculate correct servicecarscheduledetailid
                    //selectedservicecarscheduledetailid

                    // TODO: Write code
                    throw new ArgumentException("Funktionalitet ikke implementeret endnu.");
                }
                else
                {
                    selectedservicecarscheduledetailid = Convert.ToInt32(e.Parameter);
                }


                TireServiceDB db = new TireServiceDB();

                ServiceCarScheduleDetail existingdetail = new ServiceCarScheduleDetail();

                // Check if booking already exists
                if (existingservicecarscheduledetailid != 0)
                {
                    // Get existing booking
                    existingdetail = db.GetServiceCarScheduleDetail(existingservicecarscheduledetailid);

                    // Update timeslot - reset to available status
                    ServiceCarScheduleDetailBLL detailBLL = new ServiceCarScheduleDetailBLL();
                    detailBLL.MakeServiceCarScheduleDetailAvailable(db, existingdetail, true);
                }

                // Get schedule for booking
                ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetail(selectedservicecarscheduledetailid);

                if (detail == null)
                {
                    throw new ArgumentException("Booking tidsrum blev ikke fundet - venligst prøv igen.");
                }

                if (detail.ScheduleDetailTypeId != (int)Shared.ScheduleDetailType.Available)
                {
                    throw new ArgumentException("Valgte tidsrum er desværre blevet booket af en anden - venligst prøv igen.");
                }

                // Get car
                Car car = db.GetCar(carid);

                // Get customer
                Customer customer = db.GetCustomer(customerid);

                // Get task
                Task task = db.GetTask(taskid);

                // TODO: Consider updating task addresses (if replanning happens)

                // Make new booking
                // Insert car on timeslot and update scheduledetail
                detail.CarId = car.CarId;
                detail.ToTireSetId = task.TireSetId;
                detail.CustomerConfirmed = true;
                detail.ToAddress = address;
                detail.ToZipCode = zipcode;
                detail.ToCity = city;
                detail.ToCountryId = customer.CountryId;
                if (address != "" & zipcode != "" & city != "")
                {
                    // Calculate longitude and latitude for secondary address
                    try
                    {
                        string secondaryAddress = address + ", " + zipcode + " " + city + ", " + db.GetCountryName(customer.CountryId);
                        GoogleMaps googleMapAPI = new GoogleMaps(Convert.ToString(ConfigurationManager.AppSettings["MapKey"]));
                        double[] LongLatSecondary = googleMapAPI.GetLongLatCoordinates(secondaryAddress);
                        detail.ToLongitude = LongLatSecondary[0];
                        detail.ToLatitude = LongLatSecondary[1];
                    }
                    catch (Exception)
                    {
                        // Error calculating longitude and latitude - values will be set to null
                    }

                }
                else
                {
                    detail.ToLongitude = null;
                    detail.ToLatitude = null;
                }
                detail.ScheduleDetailTypeId = (int)Shared.ScheduleDetailType.ServiceDrive;
                detail.CustomerConfirmed = true;

                // Relate Task to ServiceCarScheduleDetail
                detail.TaskId = task.TaskId;

                // Update car with new status        
                car.CarStatusId = (int)Shared.CarStatus.PlannedTireChange;

                // Update Task status
                task.TaskTypeStatusId = (int)Shared.TaskTypeStatus.ServiceDrive_Planned;

                // Submit changes to database
                db.SubmitChanges();

                // Send email to customer with confirmation
                // Prepare email
                EmailNotificationServices emailService = new EmailNotificationServices();

                // Send confirmation email to customer
                emailService.Customer_ServiceDriveBookingConfirmation_SendCustomerEmail(customer.CustomerId, customer.Email, car.RegistrationNumber, customer.Name, detail.ScheduleDate.ToShortDateString(), string.Format("{0:t}", detail.StartTime) + " - " + string.Format("{0:t}", detail.EndTime), detail.ToAddress, detail.ToZipCode, detail.ToCity, null);

                // Dispose database connection
                db.Dispose();

                // Update GUI
                lnkBooking.NavigateUrl = string.Format("~/Booking/Booking.aspx?uid={0}", customer.UserId.ToString());
                lnkBooking.Text = "Online booking";

                // Prepare input (0: date, 1: starttime, 2: endtime, 3: location, 4: subject, 5: description)
                //lblOutlookAppointmentDetails.Text = detail.ScheduleDate.ToShortDateString() + "|" + detail.StartTime.ToString() + "|" + detail.EndTime.ToString() + "|" + detail.ToAddress + ", " + detail.ToZipCode + " " + detail.ToCity + "|Hjulskift på " + car.RegistrationNumber + "|Mobilhjulskift.dk kommer og skifter hjul på min bil - HUSK bilen skal holde på den aftalte lokation";
                string details = detail.ScheduleDate.ToShortDateString() + "|" + detail.StartTime.ToString() + "|" + detail.EndTime.ToString() + "|" + detail.ToAddress + ", " + detail.ToZipCode + " " + detail.ToCity + "|Hjulskift på " + car.RegistrationNumber + "|Mobilhjulskift.dk kommer og skifter hjul på min bil - HUSK bilen skal holde på den aftalte lokation";

                lnkAddOutlookAppointment.NavigateUrl = string.Format("~/Booking/OpdaterKalender.aspx?details={0}", details);
                lnkAddOutlookAppointment.Text = "Gem i Outlook";
            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side when booking is approved and update GUI, show confirmation
        /// </summary>
        protected void callbackConfirmBookingPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Save or update existing booking

            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side when error occure, show error panel/message
        /// </summary>
        protected void callbackErrorPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {

            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Function that is raised from client side and reject timeslot + send email to support
        /// </summary>
        protected void callbackNoDateFit_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                TireServiceDB db = new TireServiceDB();

                int customerid = (int)Session["BookingCustomerId"];
                int carid = (int)Session["BookingCarId"];
                int taskid = (int)Session["BookingTaskId"];

                string bookingdetails = "Ingen booking i systemet endnu";
                string date = "Ingen";

                ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetailByTaskId(taskid);

                if (detail != null)
                {
                    // Booking exists - this has been rejected
                    bookingdetails = detail.StartTime.ToString() + " - " + detail.EndTime + ": " + detail.ToAddress + ", " + detail.ToZipCode + " " + detail.ToCity;
                    date = detail.ScheduleDate.ToShortDateString();
                }
                
                
                string emailaddress = Convert.ToString(ConfigurationManager.AppSettings["EmailAddress"]);
                bool test = Convert.ToBoolean(Convert.ToByte(ConfigurationManager.AppSettings["TestEnvironmentOn"]));
                //string message = String.Format("Hjulskift dato blev afvist<br><br>Kunde har valgt{0}<br><br>Oplysninger: <br>{1}<br><br>Kommentar: {2}", rblDate.SelectedItem.Text, lServiceDetailInfo.Text, txtComment.Text);
                string message = String.Format("Hjulskift dato blev afvist<br><br>Oplysninger: <br>{0}<br><br>Kommentar/Nye dato'er: {1}", bookingdetails, e.Parameter.ToString());
                string subject = String.Format("Hjulskift dato afvist {0} Kunde {1}", date, customerid.ToString());

                Shared email = new Shared();
                email.SendEmail(emailaddress, emailaddress, message, subject, true, test, null, null, null);
            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Callback function that save outlook appointment
        /// </summary>
        protected void callbackSaveOutlookAppointment_Callback(object sender, CallbackEventArgs e)
        {
            // Get input (0: date, 1: starttime, 2: endtime, 3: location, 4: subject, 5: description)
            string[] param = e.Parameter.Split('|');

            DateTime beginDate = Convert.ToDateTime(param[0] + " " + param[1]);
            DateTime endDate = Convert.ToDateTime(param[0] + " " + param[2]);

            string myLocation = param[3];
            string mySubject = param[4];
            string myDescription = param[5];

            // Initialize
            MemoryStream mStream = new MemoryStream();
            StreamWriter writer = new StreamWriter(mStream);
            writer.AutoFlush = true;

            // Create Header
            writer.WriteLine("BEGIN:VCALENDAR");
            writer.WriteLine("PRODID:-//MOBILHJULSKIFT.DK//www.mobilhjulskift.dk//EN");
            writer.WriteLine("BEGIN:VEVENT");

            // Create Body
            writer.WriteLine("DTSTART:" + beginDate.ToUniversalTime().ToString("yyyyMMdd\\THHmmss\\Z"));
            writer.WriteLine("DTEND:" + endDate.ToUniversalTime().ToString("yyyyMMdd\\THHmmss\\Z"));
            writer.WriteLine("LOCATION:" + myLocation);
            writer.WriteLine("DESCRIPTION;ENCODING=QUOTED-PRINTABLE:" + myDescription);
            writer.WriteLine("SUMMARY:" + mySubject);

            // Create Footer
            writer.WriteLine("PRIORITY:3");
            writer.WriteLine("END:VEVENT");
            writer.WriteLine("END:VCALENDAR");

            // Make it downloadable
            Response.Clear(); // clears the current output content from the buffer
            Response.AppendHeader("Content-Disposition", "attachment; filename=hjulskift.vcs");
            Response.AppendHeader("Content-Length", mStream.Length.ToString());
            Response.ContentType = "application/download";
            Response.BinaryWrite(mStream.ToArray());
            Response.End();

            // Send internal email to ourself on this
            string emailaddress = Convert.ToString(ConfigurationManager.AppSettings["EmailAddress"]);
            bool test = Convert.ToBoolean(Convert.ToByte(ConfigurationManager.AppSettings["TestEnvironmentOn"]));
            string message = String.Format("Outlook aftale gemt " + myLocation + "(" + beginDate.ToString() + "-" + endDate.ToString() + ")");


            Shared emailBLL = new Shared();
            emailBLL.SendEmail(emailaddress, emailaddress, message, "Bruger brugte funktionen", true, test, null, null, null);
        }
    }
}